#include "MusicPlayer25A.h"
#include "./ui_MusicPlayer25A.h"

#include "Duration.hpp"

MusicPlayer25A::MusicPlayer25A(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MusicPlayer25A)
    , playlist(new Playlist(this))
    , mainPlayer(new QMediaPlayer(this))
    , vicePlayer(new QMediaPlayer(this))
    , mainAudioOutput(new QAudioOutput(this))
    , viceAudioOutput(new QAudioOutput(this))
    , prevPlaybackState(QMediaPlayer::StoppedState)
    // debug
    , latestDir("Z:/音乐 Music/Pink Floyd/1973-03-01 The Dark Side Of The Moon")
{
    mainPlayer->setAudioOutput(mainAudioOutput);
    vicePlayer->setAudioOutput(viceAudioOutput);
    switchToConnectMainPlayer();
    loadTracksFromDir(latestDir);

    ui->setupUi(this);
    ui->lisTrack->setModel(playlist);
    ui->sliDur->setEnabled(false);
    ui->labPosDif->hide();
}

MusicPlayer25A::~MusicPlayer25A() {
    delete ui;
}

void MusicPlayer25A::on_lisTrack_doubleClicked(const QModelIndex &index) {
    isPreloaded = false;
    playPlaylistAt(index.row());
}

void MusicPlayer25A::loadTracksFromDir(const QString &dir) {
    playlist->clear();
    curTrackCount = 0;

    // 打开文件夹，读取其中的音频文件
    QDirIterator it(dir,
                    {"*.mp3", "*.wav", "*.flac", "*.dsf", "*.dsd", "*.ape",
                     "*.ogg", "*.wma", "*.aac", "*.aiff", "*.m4a"});
    while (it.hasNext()) {
        auto info = it.nextFileInfo();
        Track *track = new Track(info.canonicalFilePath()); // 传入完整路径
        playlist->appendTrack(track);
        curTrackCount++;
    }
}

void MusicPlayer25A::showMetaData(Track *track) {
    if (!track->hasMetaData()) return;

    ui->labTrackTitle->setText(track->title());
    ui->labTrackArtist->setText(track->artist().join(", "));
    ui->labAlbumTitle->setText(track->albumTitle());
    ui->labAlbumArtist->setText(track->albumArtist());

    qInfo()<<"Title:"<<track->title()
           <<"Artist:"<<track->artist()
           <<"AlbumTitle:"<<track->albumTitle()
           <<"AlbumArtist:"<<track->albumArtist()
           <<"Duration:"<<track->duration();
}

void MusicPlayer25A::on_btnOpenDir_clicked() {
    // 打开文件夹选择对话框
    latestDir = QFileDialog::getExistingDirectory(this, "选择文件夹", latestDir);
    if (latestDir.isEmpty())
        return; // 没有选择文件夹，而是直接退出会话

    loadTracksFromDir(latestDir);

    // 预先准备一个随机索引序列，未测试
    // 初始化随机音轨索引序列
    // todo：每次播放列表更新时，更新随机序列
    // shuffledTrackNoList = shuffledNoList(curTrackCount);
}

void MusicPlayer25A::on_btnPlayPause_clicked() {
    switch (mainPlayer->playbackState()) {
    case QMediaPlayer::StoppedState: // 停止状态
        if (!playlist->isEmpty()) playPlaylistAt(0);
        else qInfo() << "No track file loaded.";
        break;
    case QMediaPlayer::PlayingState: // 播放状态
        pauseMainPlayer();
        break;
    case QMediaPlayer::PausedState: // 暂停状态
        resumeMainPlayer();
        break;
    }
}

void MusicPlayer25A::on_btnStop_clicked() {
    stopMainPlayer();
}

void MusicPlayer25A::on_sliDur_sliderPressed() {
    is_sliDur_UserDragging = true;
    prevTrackPos = mainPlayer->position();
    qint64 curPos = ui->sliDur->value();
    ui->labPosDif->setText(formatDur(curPos - prevTrackPos, true));
    ui->labPosDif->show();
}


void MusicPlayer25A::on_sliDur_sliderMoved(int pos) {
    ui->labPosDif->setText(formatDur(pos - prevTrackPos, true));
}

void MusicPlayer25A::on_sliDur_sliderReleased() {
    int pos = ui->sliDur->value();
    // 手动拖到进度条末尾触发无缝阈值，不做无缝直接切歌
    if (curTrack->duration() - pos < gaplessThreshold) {
        isPreloaded = false;
        stopMainPlayer();
        playNextTrack();
    }
    else {
        mainPlayer->setPosition(pos);
        // 松开进度条恢复播放
        if (is_sliDur_ReleasedToResume
            && prevPlaybackState == QMediaPlayer::PausedState)
            mainPlayer->play();
    }
    is_sliDur_UserDragging = false;
    ui->labPosDif->hide();

    qInfo()<<"Set now-playing position to"<<pos;
}

void MusicPlayer25A::showDuration(qint64 dur) {
    ui->labDur->setText(formatDur(dur));
    ui->sliDur->setMaximum(dur);
}

void MusicPlayer25A::showPosition(qint64 pos) {
    if (is_sliDur_UserDragging) return;
    // 添加阈值过滤微小抖动，当 pos 等于 0 时阈值过滤失效，以便位置 UI 归零
    if (pos && qAbs(ui->sliDur->value() - pos) < sliDur_Threshold) return;
    // 预先切歌逻辑，试实现无缝切歌
    if (curPlayOrder == Sequential
        && curTrack->duration() - pos < gaplessThreshold) {
        qInfo()<<"Gapless play hit.";
        if (nextTrackNo() >= 0) playNextTrack();
        else pos = 0;
    }
    // 懒预加载（借用的，不知道原义，依字面意思理解使用）
    if (curPlayOrder == Sequential // 顺序播放（待扩展：列表循环）
        && doPreloading // 要做预加载
        && !vicePlayer->isPlaying() // 副播放器不在播放
        && nextTrackNo() >= 0 // 下一音轨有效
        && curTrack->duration() / 2 - pos < 0) // 进度过半
        preloadNextTrack();

    ui->labPos->setText(formatDur(pos));
    ui->sliDur->setValue(pos);
}

void MusicPlayer25A::playNextTrack() {
    if (curTrackNo == -1) return;
    if (nextTrackNo() >= 0) playPlaylistAt(nextTrackNo());
    else stopMainPlayer();
}

void MusicPlayer25A::playPrevTrack() {
    if (curTrackNo == -1) return;
    if (prevTrackNo() >= 0) playPlaylistAt(prevTrackNo());
    else stopMainPlayer();
}

void MusicPlayer25A::handleMetaDataChanged() {
    // 获取发送信号的 QMediaPlayer
    QMediaPlayer* senderPlayer = qobject_cast<QMediaPlayer*>(sender());
    bool isVice = senderPlayer == vicePlayer;
    Track* loadedTrack = playlist->fromPath(senderPlayer->source());
    loadedTrack->setMetaData(senderPlayer->metaData());
    if (!isVice) showMetaData(loadedTrack);
}

void MusicPlayer25A::handleMediaStatusChanged(QMediaPlayer::MediaStatus status) {
    // 获取发送信号的 QMediaPlayer
    QMediaPlayer* senderPlayer = qobject_cast<QMediaPlayer*>(sender());
    bool isVice = senderPlayer == vicePlayer;
    switch (status) {
    case QMediaPlayer::EndOfMedia:
        break;
    case QMediaPlayer::LoadedMedia:
        if (isVice) {
            qInfo()<<"Vice Preloaded Completed.";
            isPreloaded = true;
        }
        else ui->labPosDif->hide();
        break;
    case QMediaPlayer::NoMedia:
    case QMediaPlayer::LoadingMedia:
        if (!isVice) {
            ui->labPosDif->setText("正在加载音频……");
            ui->labPosDif->show();
        }
        break;
    case QMediaPlayer::StalledMedia:
    case QMediaPlayer::BufferingMedia:
        if (!isVice) {
            ui->labPosDif->setText("正在缓冲音频……");
            ui->labPosDif->show();
        }
        break;
    case QMediaPlayer::BufferedMedia:
        if (!isVice) ui->labPosDif->hide();
        break;
    case QMediaPlayer::InvalidMedia:
        break;
    }
}

void MusicPlayer25A::handlePlaybackStateChanged(QMediaPlayer::PlaybackState state) {
    switch (state) {
    case QMediaPlayer::PlayingState:
        if (prevPlaybackState == QMediaPlayer::StoppedState) showDuration(curTrack->duration());
        if (!ui->sliDur->isEnabled()) ui->sliDur->setEnabled(true);
        break;
    case QMediaPlayer::PausedState:
        break;
    case QMediaPlayer::StoppedState:
        showDuration(0);
        ui->sliDur->setEnabled(false);
        break;
    }
    prevPlaybackState = state;
}

void MusicPlayer25A::playPlaylistAt(int no) {
    if (no < 0 || no >= curTrackCount) return;
    if (no == curTrackNo) mainPlayer->setPosition(0);
    else {
        curTrack = playlist->at(no);
        if (curPlayOrder == Sequential && isPreloaded && no == nextTrackNo())
        { switchMainPlayer(); showMetaData(curTrack); doPreloading = true; }
        else mainPlayer->setSource(curTrack->path());
        curTrackNo = no;
    }
    mainPlayer->play();
    if (curTrack->hasMetaData()) showMetaData(curTrack);

    qInfo()<<"Now Playing:"<<curTrack->fileName();
}

void MusicPlayer25A::pauseMainPlayer() {
    mainPlayer->pause();
}

void MusicPlayer25A::resumeMainPlayer() {
    mainPlayer->play();
}

void MusicPlayer25A::stopMainPlayer() {
    mainPlayer->stop();

    showDuration(0);
    ui->sliDur->setEnabled(false);
}

void MusicPlayer25A::on_btnNextTrack_clicked() {
    isPreloaded = false;
    playNextTrack();
}


void MusicPlayer25A::on_btnPrevTrack_clicked() {
    isPreloaded = false;
    playPrevTrack();
}


void MusicPlayer25A::on_btnPlayOrder_clicked() {
    curPlayOrderIndex = (curPlayOrderIndex+1) % lenPlayOrder;
    curPlayOrder = arrPlayOrder[curPlayOrderIndex];
    ui->btnPlayOrder->setText(arrPlayOrderText[curPlayOrderIndex]);
}

int MusicPlayer25A::nextTrackNo() {
    int nextTrackNo = curTrackNo;
    switch (curPlayOrder) {
    case Sequential:
        nextTrackNo = curTrackNo + 1;
        if (nextTrackNo >= curTrackCount) return -1;
        break;
    case LoopList:
        nextTrackNo = (curTrackNo+1) % curTrackCount;
        break;
    case LoopSingle:
        break;
    case Shuffle:
        // 使用预先准备的随机索引序列，未测试
        // while (shuffledTrackNoList->at(nextTrackNo) != curTrackNo)
        //     nextTrackNo = (nextTrackNo+1) % curTrackCount;
        // nextTrackNo = shuffledTrackNoList->at((nextTrackNo+1) % curTrackCount);
        // 简单的不重复随机
        do nextTrackNo = QRandomGenerator::global()->bounded(curTrackCount);
        while (nextTrackNo == curTrackNo);
        break;
    }
    return nextTrackNo;
}

int MusicPlayer25A::prevTrackNo() {
    int prevTrackNo = curTrackNo;
    switch (curPlayOrder) {
    case Sequential:
        prevTrackNo = curTrackNo - 1;
        if (prevTrackNo < 0) return -1;
        break;
    case LoopList:
        prevTrackNo = (curTrackNo-1+curTrackCount) % curTrackCount;
        break;
    case LoopSingle:
        break;
    case Shuffle:
        do prevTrackNo = QRandomGenerator::global()->bounded(curTrackCount);
        while (prevTrackNo == curTrackNo);
        break;
    }
    return prevTrackNo;
}

void MusicPlayer25A::preloadNextTrack() {
    doPreloading = false;
    isPreloaded = false;
    Track *nextTrack = playlist->at(nextTrackNo());

    qInfo()<<"Preloading:"<<nextTrack->fileName();

    vicePlayer->setSource(nextTrack->path());
}

void MusicPlayer25A::switchMainPlayer() {
    qInfo()<<"Switching Main & Vice player.";

    // 交换主副播放器
    std::swap(mainPlayer, vicePlayer);

    // 换接主副播放器
    switchToConnectMainPlayer();

    // 更新全局变量
    prevPlaybackState = mainPlayer->playbackState();
}

void MusicPlayer25A::switchToConnectMainPlayer() {
    if (!isInitedConnection) {
        connect(mainPlayer, &QMediaPlayer::metaDataChanged, this, &MusicPlayer25A::handleMetaDataChanged);
        connect(mainPlayer, &QMediaPlayer::mediaStatusChanged, this, &MusicPlayer25A::handleMediaStatusChanged);
        connect(vicePlayer, &QMediaPlayer::metaDataChanged, this, &MusicPlayer25A::handleMetaDataChanged);
        connect(vicePlayer, &QMediaPlayer::mediaStatusChanged, this, &MusicPlayer25A::handleMediaStatusChanged);
        isInitedConnection = true;
    }

    // 连接主播放器
    connect(mainPlayer, &QMediaPlayer::positionChanged, this, &MusicPlayer25A::showPosition);
    // connect(mainPlayer, &QMediaPlayer::durationChanged, [this]() { curTrackDur = mainPlayer->duration(); });
    connect(mainPlayer, &QMediaPlayer::playbackStateChanged, this, &MusicPlayer25A::handlePlaybackStateChanged);

    // 断连副播放器
    disconnect(vicePlayer, &QMediaPlayer::positionChanged, this, &MusicPlayer25A::showPosition);
    disconnect(vicePlayer, &QMediaPlayer::playbackStateChanged, this, &MusicPlayer25A::handlePlaybackStateChanged);
}

void MusicPlayer25A::on_btnVolume_clicked() {
    // debug
    // switchMainPlayer();
    // mainPlayer->play();
}
